package org.example.mall.admin.service.manage.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.example.mall.admin.configuration.exception.BaseException;
import org.example.mall.admin.constant.CommonConstants;
import org.example.mall.admin.mapper.manage.MenuMapper;
import org.example.mall.admin.model.entity.manage.Menu;
import org.example.mall.admin.model.enums.manage.MenuTypeEnum;
import org.example.mall.admin.model.enums.manage.SysRelationEnum;
import org.example.mall.admin.service.manage.MenuService;
import org.example.mall.admin.service.manage.SysRelationService;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单权限表 服务实现类
 * </p>
 *
 * @author hzq
 * @since 2021-12-29
 */
@Service
@AllArgsConstructor
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    private final SysRelationService sysRelationService;

    @Override
    public List<GrantedAuthority> accountAuthorities(Integer accountId, String clientId) {

        List<Menu> menus = accountMenus(accountId, clientId);

        return AuthorityUtils.createAuthorityList(menus.stream()
                .filter(m -> m.getType().equals(MenuTypeEnum.BUTTON.getType()) && StrUtil.isNotBlank(m.getType()))
                .map(Menu::getPermission).distinct().toArray(String[]::new));
    }

    @Override
    public List<Menu> accountMenus(Integer accountId, String clientId) {
        return getBaseMapper().accountMenus(accountId, clientId);
    }

    @Override
    public List<Tree<Integer>> filterMenu(Set<Menu> menus, String type, Integer parentId) {
        List<TreeNode<Integer>> collect = menus.stream()
                .filter(menuTypePredicate(type))
                .map(getNodeFunction())
                .collect(Collectors.toList());
        Integer parent = parentId == null ? CommonConstants.MENU_TREE_ROOT_ID : parentId;
        return TreeUtil.build(collect, parent);
    }

    /**
     * 构建树查询
     * 1. 不是懒加载情况，查询全部
     * 2. 是懒加载，根据parentId 查询
     * 2.1 父节点为空，则查询ID -1
     *
     * @param clientId 客户端id
     * @param lazy     是否是懒加载
     * @param parentId 父节点ID
     */
    @Override
    public List<Tree<Integer>> treeMenu(String clientId, boolean lazy, Integer parentId) {

        if (!lazy) {
            List<TreeNode<Integer>> collect = list(Wrappers.<Menu>lambdaQuery()
                    .eq(Menu::getClientId, clientId).orderByAsc(Menu::getSort)).stream()
                    .map(getNodeFunction()).collect(Collectors.toList());
            return TreeUtil.build(collect, CommonConstants.MENU_TREE_ROOT_ID);
        }

        Integer parent = parentId == null ? CommonConstants.MENU_TREE_ROOT_ID : parentId;
        List<TreeNode<Integer>> collect = list(Wrappers.<Menu>lambdaQuery()
                .eq(Menu::getParentId, parent).eq(Menu::getClientId, clientId).orderByAsc(Menu::getSort))
                .stream().map(getNodeFunction()).collect(Collectors.toList());

        return TreeUtil.build(collect, parent);
    }

    @Override
    public List<Menu> findMenusByRoleId(Integer roleId) {
        return getBaseMapper().findMenusByRoleId(roleId);
    }

    @Override
    @Transactional
    public Boolean removeMenuById(Integer menuId) {

        List<Menu> subMenus = list(Wrappers.<Menu>query().lambda().eq(Menu::getParentId, menuId));
        if (CollUtil.isNotEmpty(subMenus)) {
            throw new BaseException("菜单含有下级不能删除");
        }

        // 删除菜单角色关联
        sysRelationService.delRelationToId(menuId, SysRelationEnum.ROLE_MENU.getTbName());

        return removeById(menuId);
    }

    @NotNull
    private Function<Menu, TreeNode<Integer>> getNodeFunction() {
        return menu -> {
            TreeNode<Integer> node = new TreeNode<>();
            node.setId(menu.getMenuId());
            node.setName(menu.getName());
            node.setParentId(menu.getParentId());
            node.setWeight(menu.getSort());
            // 扩展属性
            Map<String, Object> extra = new HashMap<>();
            extra.put("icon", menu.getIcon());
            extra.put("path", menu.getPath());
            extra.put("type", menu.getType());
            extra.put("permission", menu.getPermission());
            extra.put("label", menu.getName());
            extra.put("sort", menu.getSort());
            extra.put("keepAlive", menu.getKeepAlive());
            node.setExtra(extra);
            return node;
        };
    }

    /**
     * menu 类型断言
     *
     * @param type 类型
     * @return Predicate
     */
    private Predicate<Menu> menuTypePredicate(String type) {
        return vo -> {
            if (MenuTypeEnum.TOP_MENU.getDescription().equals(type)) {
                return MenuTypeEnum.TOP_MENU.getType().equals(vo.getType());
            }
            // 其他查询 左侧 + 顶部
            return !MenuTypeEnum.BUTTON.getType().equals(vo.getType());
        };
    }
}
